package com.pat.jrgwt.client;

import java.util.Date;

import org.apache.commons.lang.NotImplementedException;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.DoubleBox;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HTMLTable.Cell;
import com.google.gwt.user.client.ui.HasText;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.HasHorizontalAlignment.HorizontalAlignmentConstant;
import com.google.gwt.util.tools.shared.StringUtils;
import com.pat.jrgwt.shared.MyConstants;

public class EuroConversion extends Composite
{

    private static EuroConversionUiBinder uiBinder = GWT
            .create(EuroConversionUiBinder.class);

    interface EuroConversionUiBinder extends UiBinder<Widget, EuroConversion>
    {
    }
    
    /**
     * Contains values to convert currencies
     */
    protected double[][] m_conversions = null;
    
    protected DoubleBox m_doubleBox = new DoubleBox();

    protected HandlerRegistration handler = null;

    private static class SingletonHolder
    {
        private static final EuroConversion instance = new EuroConversion();
    }
    
    public static EuroConversion getInstance()
    {
        return SingletonHolder.instance;
    }
    
    @UiField Grid EuroGrid; 
    
    private EuroConversion()
    {
        initWidget(uiBinder.createAndBindUi(this));
        
        JrcEventsLog.getInstance().add("Initializing EuroConv...");

        formatEuroGrid();
        
        loadInitialData();
        
        recalculate();
        
        handler = EuroGrid.addClickHandler(new EuroGridClickHandler());
    }

    protected class EuroGridClickHandler implements ClickHandler
    {
        
        @Override
        public void onClick(ClickEvent event)
        {
            Cell cell = EuroGrid.getCellForEvent(event);
            final int row = cell.getRowIndex();
            final int column = cell.getCellIndex();
            
            // Not widget, just header
            if( row < 1 || column < 1 )
            {
                return;
            }
            
            handler.removeHandler();
            
            final DoubleBox db = new DoubleBox();
            final TextBox tb = new TextBox();
            final Double originalValue = m_conversions[row - 1][column - 1];
            db.setWidth("60px");
            tb.setWidth("60px");
            tb.addKeyDownHandler(new KeyDownHandler()
            {
                
                @Override
                public void onKeyDown(KeyDownEvent event)
                {
//                    Window.alert("Key code: " + event.getNativeKeyCode());
                    if( event.getNativeKeyCode() == KeyCodes.KEY_ENTER )
                    {
//                        Window.alert("Setting value from cell: " + tb.getValue());
//                        m_conversions[row - 1][column - 1] = db.getValue();
                        m_conversions[row - 1][column - 1] = Double.parseDouble(tb.getValue());
                        EuroGrid.setText(row, column, "" + m_conversions[row - 1][column - 1]);
                        handler = EuroGrid.addClickHandler(new EuroGridClickHandler());
                    }else if( event.getNativeKeyCode() == KeyCodes.KEY_ESCAPE )
                    {
                        // Restoring original value, w/o changing
                        EuroGrid.setText(row, column, "" + originalValue);
                        handler = EuroGrid.addClickHandler(new EuroGridClickHandler());
                    }
                }
                
            });
//            db.setValue(m_conversions[row - 1][column - 1]);
//            Window.alert("Value of cell is: " + m_conversions[column - 1][row - 1]);
            tb.setValue("" + m_conversions[row - 1][column - 1]);
            EuroGrid.setWidget(row, column, tb);
//            EuroGrid.setWidget(row, column, db);
//            db.setFocus(true);
            tb.setFocus(true);
        }
    }
    
    protected void loadInitialData()
    {
//        double[] ar = new double[] {
//                // EURUSD
//                1.36928, 1.38056, 1.41574, 1.48022, 1.43956, 1.45017, 1.43979, -1.00000, -1.00000, -1.00000, -1.00000, -1.00000
//                // EURJPY
//                , 112.321, 112.898, 117.675, 120.120, 117.358, 116.833, 110.556, -1.000, -1.000, -1.000, -1.000, -1.000
//                // EURGBP
//                , 0.85499, 0.84910, 0.88317, 0.88547, 0.87517, 0.90344, 0.87645, -1.00000, -1.00000, -1.00000, -1.00000, -1.00000
//                // EURCHF
//                , 1.29252, 1.28212, 1.30094, 1.28068, 1.22913, 1.21887, 1.13110, -1.00000, -1.00000, -1.00000, -1.00000, -1.00000
//                // EURAUD
//                , 1.37269, 1.35518, 1.37052, 1.34904, 1.34884, 1.35242, 1.30917, -1.00000, -1.00000, -1.00000, -1.00000, -1.00000
//                // EURNZD
//                , 1.78835, 1.83453, 1.85839, 1.82741, 1.74549, 1.74813, 1.63646, -1.00000, -1.00000, -1.00000, -1.00000, -1.00000
//                // EURCAD
//                , 1.37035, 1.34117, 1.37397, 1.39709, 1.39437, 1.39693, 1.37530, -1.00000, -1.00000, -1.00000, -1.00000, -1.00000
//        };
        
        m_conversions = new double[12][7];
        
    }
    
    /**
     * Re-draws data 
     */
    public void recalculate()
    {
//        Window.alert("Columns: " + m_conversions.length);
//        Window.alert("Rows: " + m_conversions[0].length);
        for (int month = 0; month < m_conversions.length; month++)
        {
            String s = "";
            for(int z = 0; z < m_conversions[month].length; z++){ s += m_conversions[month][z] + ":"; }
//            Window.alert("Filling row #" + month + " with: " + s);
            for (int r = 0; r < m_conversions[month].length; r++)
            {
                EuroGrid.setText(month + 1, r + 1, "" + m_conversions[month][r]);
            }
        }
    }

    public void setData(double[][] arConv)
    {
        m_conversions = arConv;
    }
    
    @SuppressWarnings("deprecation")
    protected void formatEuroGrid()
    {
        EuroGrid.resize(13, 8);
        
        String[] arHeader = new String[]{ "", "EURUSD", "EURJPY", "EURGBP", "EURCHF", "EURAUD", "EURNZD", "EURCAD" };

        for( int i = 0; i < EuroGrid.getColumnCount(); i++ )
        {
            EuroGrid.getCellFormatter().setWidth(0, i, "200");
            EuroGrid.setText(0, i, (i < arHeader.length) ? "" + arHeader[i] : "");
        }
        
        String[] ar = new String[]{ "", "Jan.", "Feb.", "Mar.", "Apr.", "May", "Jun.", "Jul.", "Aug.", "Sep.", "Oct.", "Nov. ", "Dec." };
        for( int i = 0; i < EuroGrid.getRowCount(); i++ )
        {
            EuroGrid.setText(i, 0, ar[i]);
        }

        final ListBox lstYear = new ListBox();
        lstYear.addChangeHandler(new ChangeHandler()
        {
            
            @Override
            public void onChange(ChangeEvent event)
            {
                final int year = lstYear.getSelectedIndex() < 0 ? 0 : Integer.parseInt(lstYear.getItemText(lstYear.getSelectedIndex()));
//                loadForYear(year);
//                Window.alert("New year is: " + year);
            }
        });
        Date now = new Date();
        
        // Loading conversion data
//        loadForYear(1900 + now.getYear());
        
        // Filling list of years
        for (int i = 104; i < now.getYear() + 1; i++)
        {
            lstYear.addItem("" + (1900 + i));
            if( i == now.getYear() )
            {
                lstYear.setSelectedIndex(i - 104);
            }
        }
        EuroGrid.setWidget(0, 0, lstYear);
        
    }
    
//    public void loadForYear(final int year)
//    {
//        JrcEventsLog.getInstance().add("Loading conversion for year " + year);
//
//        JsonRequest.get(MyConstants.EXCHANGE_SERVER_URL + "pet/geteuroconv?year=" + year + "&callback=", new JsonRequestHandler()
//        {
//            
//            @Override
//            public void onRequestCompleted(JavaScriptObject json)
//            {
//                JrcEventsLog.getInstance().add("Got data for year " + year);
////                Window.alert("Got JSON for " + year);
//                double[][] arConv = EuroConversion.parseAndStoreJson(json);
//                if( arConv != null )
//                {
//                    setData(arConv);
//                    refreshGrid();
//                }
//            }
//        });
//    }

    public EuroConversion(String firstName)
    {
        initWidget(uiBinder.createAndBindUi(this));
    }

    /**
     * Returns array of Euro conversion from JSON data
     * @param jso JSON data from ITTC
     * @return
     */
    public static double[][] parseJsonData(JavaScriptObject jso)
    {
        JSONObject jsonObj = new JSONObject(jso);
        double[][] arConv = null;

        try
        {
            arConv = new double[jsonObj.keySet().size()][7];
            double conv = 0;
            for (String k : jsonObj.keySet())
            {
                int month = Integer.parseInt(k);
                //Window.alert(k);
                JSONArray ar = jsonObj.get(k).isArray();
                //Window.alert(k + ": " + ((ar == null) ? "EMPTY" : "OK"));
                for (int i = 0; i < ar.size(); i++)
                {
//                    Window.alert(k + ": " + ar.get(i));
                    conv = Double.parseDouble(ar.get(i).toString().replaceAll("\"", ""));
                    arConv[month - 1][i] = conv;
                }
            }
        }
        catch (Exception e)
        {
//            Window.alert("Error parsing EuroConversion JSON from ITTC server! " + e.toString());
            GWT.log("Error parsing EuroConversion JSON from ITTC server! " + e.toString());
            arConv = null;
        }
        
        return arConv;
    }

    public double getRatio(String exchangeName, int month)
    {
        String[] m_arExchanges = new String[]{ "", "EURUSD", "EURJPY", "EURGBP", "EURCHF", "EURAUD", "EURNZD", "EURCAD" };
        int pos = -1;
        double v = Double.MIN_VALUE;
        
        for( int i = 0; (pos < 0) && (i < m_arExchanges.length); i++ )
        {
            if( exchangeName == m_arExchanges[i] )
            {
                pos = i;
            }
        }
        
//        GWT.log("Position of exchange " + exchangeName + " is " + pos);
        if( pos != -1 )
        {
            v = m_conversions[month - 1][pos - 1];
        }
        
        return v;
    }

}
